// Copyright (c) 2025, 大连理工大学 (Dalian University of Technology)
//
// Licensed under the Mulan PSL v2.
// You can use this file according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of the License at
//
//     http://license.coscl.org.cn/MulanPSL2
//
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. SEE THE MULAN PSL v2
// FOR MORE DETAILS.

#include "DBManager/Service/Input/Load/LoadSummaryService.h"

#include <cassert>
#include <cstddef>
#include <list>
#include <vector>

#include "Utility/Algebra/Matrix.h"

#include "DataStructure/Common/Id.h"
#include "DataStructure/Input/Load/LoadTypes.h"

#include "DBManager/Common/ServiceMacro.h"
#include "DBManager/IRepository/Input/Load/IGRAVRepository.h"
#include "DBManager/IRepository/Input/Load/ILoadSummaryRepository.h"
#include "DBManager/Service/Input/Load/LoadSummaryService.h"

#include "LoadSummaryService.h"

using namespace SG::DBManager;

SERVICE_REG_FOR_SUMMARY (LoadSummaryService, ILoadSummaryRepository)

namespace
{
    std::vector<LoadSummaryService::SummaryCreateService>* g_summaryCreateLoadService = nullptr;
}

LoadSummaryService::LoadSummaryService (DBServiceFactory* const dbServiceFactory, ILoadSummaryRepository& repos)
    : InputServiceBase<ILoadSummaryRepository> (dbServiceFactory, repos)
{}

LoadSummaryService::~LoadSummaryService () = default;

SG::DataStructure::FEM::LoadTypeSet LoadSummaryService::GetLoadType (SG::DataStructure::Common::Id sid) const
{
    return m_repository.GetLoadType (sid);
}

std::vector<SG::DataStructure::Common::Id> LoadSummaryService::GetAllId () const
{
    return m_repository.GetAllId ();
}

std::vector<SG::DataStructure::FEM::GRAVData> LoadSummaryService::FindGRAV (std::set<SG::DataStructure::Common::Id> loadCases) const
{
    auto gravRepos = m_dbServiceFactory->GetDatabase ()->GetRepository<IGRAVRepository> ();

    // 存储了所有的载荷，以及其类型
    auto loadSummaryMap = m_repository.GetAllMap ();

    SG::DataStructure::FEM::GRAVData grav;

    std::vector<SG::DataStructure::FEM::GRAVData> result;

    for (auto&& sid : loadCases)
    {
        auto it = loadSummaryMap.find (sid);
        if (it != loadSummaryMap.end ())
        {
            const auto& types = it->second.m_type;

            if (std::find_if (
                    types.begin (), types.end (), [] (auto type) { return type == SG::DataStructure::FEM::LoadType::LOAD_Gravity; })
                != types.end ())
            {
                if (gravRepos->FindById (sid, grav) == SG::DataStructure::Common::Status::STATUS_Success)
                {
                    result.push_back (grav);
                }
            }
        }
    }
    return result;
}

SG::DataStructure::Common::Status LoadSummaryService::CopyData (DBServiceFactory* const                    dest,
                                                                std::vector<SG::DataStructure::Common::Id> ids) const
{
    std::map<std::size_t, std::list<SG::DataStructure::Common::Id>> map;
    for (auto&& id : ids)
    {
        auto types = GetLoadType (id);
        for (auto&& type : types)
        {
            std::size_t typeId = typeid (decltype (type)).hash_code () + type;

            if (map.find (typeId) == map.end ())
            {
                map[typeId] = std::list<SG::DataStructure::Common::Id> ();
            }
            map[typeId].push_back (id);
        }
    }

    auto funMap = m_dbServiceFactory->GetDatabase ()->GetHub ()->CopyDataFunMap ();
    for (auto&& pair : map)
    {
        if (funMap.count (pair.first) > 0)
        {
            funMap[pair.first](m_dbServiceFactory, dest, { pair.second.begin (), pair.second.end () });
        }
    }

    return SG::DataStructure::Common::Status::STATUS_Success;
}

bool LoadSummaryService::RegisterService (SummaryCreateService&& service)
{
    if (g_summaryCreateLoadService == nullptr)
        ::g_summaryCreateLoadService = new std::vector<SummaryCreateService> ();

    ::g_summaryCreateLoadService->emplace_back (std::move (service));
    return true;
}

void LoadSummaryService::CreateSummary (DBServiceFactory* const dbServiceFactory)
{
    if (g_summaryCreateLoadService != nullptr)
        for (size_t i = 0; i < g_summaryCreateLoadService->size (); i++)
        {
            g_summaryCreateLoadService->at (i) (dbServiceFactory);
        }
}
